package org.covalence.core.visitor;

import org.apache.log4j.Logger;
import org.covalence.core.Constants;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class SetObservableMethodVisitor extends MethodAdapter 
		implements Opcodes, Constants {

	private String className;

	private String property;
	
	private String desc;

	private static Logger log = 
		Logger.getLogger(SetObservableMethodVisitor.class);

	public SetObservableMethodVisitor(MethodVisitor mv, String className, 
			String property, String typeDescriptor) {

		super(mv);
		this.className = className;
		this.property = property;
		this.desc = typeDescriptor;

		log.trace("[classname:" + className + 
				", property: " + property +
				", desc: " + this.desc + "]");
	}

	@Override
	public void visitCode() {
		// if (property instanceof Observable && ((Observable) property).getParent() != this) {
    	//	  addNestedObservable((Observable) property, "property");
		//    ((Observable)property).setParent(this);
		//    this._pcs.
    	// }
		Label l0 = new Label();
		mv.visitLabel(l0);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitTypeInsn(INSTANCEOF, OBSERVABLE);
		Label l1 = new Label();
		mv.visitJumpInsn(IFEQ, l1);
		Label l2 = new Label();
		mv.visitLabel(l2);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitTypeInsn(CHECKCAST, OBSERVABLE);
		mv.visitMethodInsn(INVOKEINTERFACE, OBSERVABLE, "getParent", 
				GET_PARENT_SIG);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitJumpInsn(IF_ACMPEQ, l1);
		Label l3 = new Label();
		mv.visitLabel(l3);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitTypeInsn(CHECKCAST, OBSERVABLE);
		mv.visitLdcInsn(this.property);
		mv.visitMethodInsn(INVOKEVIRTUAL, this.className, 
				"addNestedObservable", ADD_NESTED_OBSERVABLE_SIG);
		Label l4 = new Label();
		mv.visitLabel(l4);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitTypeInsn(CHECKCAST, OBSERVABLE);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitMethodInsn(INVOKEINTERFACE, OBSERVABLE, "setParent", 
				SET_PARENT_SIG);
		
		mv.visitVarInsn(ALOAD, 0);
		mv.visitFieldInsn(GETFIELD, this.className, 
				PROPERTY_CHANGE_SUPPORT_FIELD, 
				CPROPERTY_CHANGE_SUPPORT_TYPE);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitFieldInsn(GETFIELD, this.className, this.property, this.desc);
		mv.visitTypeInsn(CHECKCAST, OBSERVABLE);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitTypeInsn(CHECKCAST, OBSERVABLE);
		mv.visitMethodInsn(INVOKEVIRTUAL, CPROPERTY_CHANGE_SUPPORT, 
				"moveListeners", 
				MOVE_LISTENERS_SIG);

		mv.visitLabel(l1);
		super.visitCode();
	}	
}
